home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 7684 / 7684.xpi / resources / fmPlayerInitializer.js < prev    next >
Text File  |  2009-11-20  |  13KB  |  412 lines

  1. /**
  2.  * Copyright (c) 2008, Jose Enrique Bolanos, Jorge Villalobos
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions are met:
  7.  *
  8.  *  * Redistributions of source code must retain the above copyright notice,
  9.  *    this list of conditions and the following disclaimer.
  10.  *  * Redistributions in binary form must reproduce the above copyright notice,
  11.  *    this list of conditions and the following disclaimer in the documentation
  12.  *    and/or other materials provided with the distribution.
  13.  *  * Neither the name of Jose Enrique Bolanos, Jorge Villalobos nor the names
  14.  *    of its contributors may be used to endorse or promote products derived
  15.  *    from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  20.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
  21.  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  22.  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  23.  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  24.  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  25.  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  26.  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  **/
  29.  
  30. var EXPORTED_SYMBOLS = [];
  31.  
  32. const Cc = Components.classes;
  33. const Ci = Components.interfaces;
  34. const Ce = Components.Exception;
  35.  
  36. Components.utils.import("resource://firefm/fmCommon.js");
  37. Components.utils.import("resource://firefm/fmPlayer.js");
  38.  
  39. // Name of the permission file
  40. const PERMISSION_FILE_NAME = "firefm.cfg";
  41. // Strings passed to the directory service to obtain the application data
  42. // folder on each OS
  43. const LOCATIONS = [
  44.   // Windows
  45.   "AppData",
  46.   // Mac
  47.   "UsrPrfs",
  48.   // Unix
  49.   "Home"
  50. ];
  51. // Directory path to the permission file for each OS
  52. const DIR_PATH = [
  53.   // Windows
  54.   ["Macromedia", "Flash Player", "#Security", "FlashPlayerTrust"],
  55.   // Mac
  56.   ["Macromedia", "Flash Player", "#Security", "FlashPlayerTrust"],
  57.   // Unix
  58.   [".macromedia", "Flash_Player", "#Security", "FlashPlayerTrust"]
  59. ];
  60.  
  61. // UUIDs of extensions that interfere with Fire.fm
  62. const NOSCRIPT_UUID = "{73a6fe31-595d-460b-a920-fcc0f8843232}";
  63. const FLASHBLOCK_UUID = "{3d7eb24f-2740-49df-8937-200b1cc08f8a}";
  64. const STOPAUTOPLAY_UUID = "{2e61e246-e640-4c56-b1ed-f146dbed48cd}";
  65. const MEDIAWRAP_UUID = "{dd68c513-9296-4b63-8d8b-8f1c991c8a48}";
  66.  
  67. // Flashblock and similar extensions timeout.
  68. const FLASHBLOCK_TIMEOUT = 100;
  69.  
  70. /**
  71.  * FireFM Player Initializer. Performs all the flash player intialization tasks.
  72.  */
  73. FireFM.PlayerInitializer = {
  74.  
  75.   /* Logger for this object */
  76.   _logger : null,
  77.   /* Holds the exception that may have been thrown during initialization */
  78.   _initializationException : null,
  79.  
  80.   /**
  81.    * Initializes the object.
  82.    */
  83.   init : function() {
  84.     this._logger = FireFM.getLogger("FireFM.PlayerInitializer");
  85.     this._logger.debug("init");
  86.  
  87.     this._initializeFlashPlayer();
  88.   },
  89.  
  90.   /**
  91.    * Obtains the exception that may have been thrown during the flash player
  92.    * initialization. Null if no exception was thrown.
  93.    */
  94.   get initializationException() {
  95.     this._logger.debug("initializationException[get]");
  96.     return this._initializationException;
  97.   },
  98.  
  99.   /**
  100.    * Initializes the flash object needed to play mp3 files. Steps:
  101.    * 1. The flash plugin is detected.
  102.    * 2. The flash player URL is calculated.
  103.    * 3. The flash player permission file is installed.
  104.    * 4. The flash player object is injected in the hidden window.
  105.    * After the initialization tasks are complete, FireFM.Player is initialized
  106.    * with the results.
  107.    */
  108.   _initializeFlashPlayer : function() {
  109.     this._logger.trace("_initializeFlashPlayer");
  110.  
  111.     try {
  112.       // test error line. Comment out on releases!
  113.       //null.hello;
  114.  
  115.       if (this._detectFlashPlugin()) {
  116.         let flashURL = this._getFlashURL();
  117.  
  118.         this._installPermissionFile(flashURL);
  119.  
  120.         if (this._isExtensionInstalled(NOSCRIPT_UUID)) {
  121.           this._overrideNoscript(flashURL);
  122.         }
  123.  
  124.         // these add-ons use bindings with CSS in order to change embed
  125.         // elements. We use our own CSS to override them.
  126.         if (this._isExtensionInstalled(FLASHBLOCK_UUID) ||
  127.             this._isExtensionInstalled(STOPAUTOPLAY_UUID) ||
  128.             this._isExtensionInstalled(MEDIAWRAP_UUID)) {
  129.           let that = this;
  130.           let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
  131.  
  132.           // XXX: we need a timeout here because we need to give the add-ons
  133.           // enough time to finish setting up. This way we're sure that our
  134.           // measures will work correctly.
  135.           timer.initWithCallback(
  136.             { notify :
  137.                 function(aTimer) {
  138.                   that._overrideFlashCSS();
  139.                   that._finishPlayerInit(flashURL);
  140.                 }
  141.             },
  142.             FLASHBLOCK_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT);
  143.         } else {
  144.           this._finishPlayerInit(flashURL);
  145.         }
  146.       } else {
  147.         this._logger.warn("Flash plugin missing");
  148.         FireFM.Player.initializePlayer(
  149.           null, FireFM.Player.STATUS_PLUGIN_MISSING);
  150.       }
  151.     } catch (e) {
  152.       this._logger.fatal("Flash player initialization failed:\n" + e);
  153.       this._initializationException = e;
  154.       FireFM.Player.initializePlayer(null, FireFM.Player.STATUS_LOAD_ERROR);
  155.     }
  156.   },
  157.  
  158.   /**
  159.    * Finishes the initialization of the Flash player.
  160.    * @param aURL the url of the Flash file to load.
  161.    */
  162.   _finishPlayerInit : function(aURL) {
  163.     this._logger.trace("_finishPlayerInit");
  164.  
  165.     let flashObject = this._injectFlash(aURL);
  166.  
  167.     this._logger.info("Flash player initialized successfully");
  168.     FireFM.Player.initializePlayer(flashObject, FireFM.Player.STATUS_READY);
  169.   },
  170.  
  171.   /**
  172.    * Detects if the flash player plugin is installed, enabled, and of the
  173.    * required version.
  174.    * @return True of the plugin meets the requirements, false otherwise.
  175.    */
  176.   _detectFlashPlugin : function() {
  177.     this._logger.trace("_detectFlashPlugin");
  178.  
  179.     // Regular expression to obtain the flash plugin version from its
  180.     // description.
  181.     const REGEX_FLASH_VERSION = /([0-9]+)[^0-9]/gi;
  182.     // Minimum flash version supported
  183.     const MIN_FLASH_VERSION = 8;
  184.  
  185.     let isValidPlugin = false;
  186.  
  187.     let plugin =
  188.       Cc["@mozilla.org/appshell/appShellService;1"].
  189.         getService(Ci.nsIAppShellService).hiddenDOMWindow.
  190.           navigator.mimeTypes["application/x-shockwave-flash"];
  191.  
  192.     if (plugin && plugin.enabledPlugin && plugin.enabledPlugin.description) {
  193.  
  194.       let match = REGEX_FLASH_VERSION.exec(plugin.enabledPlugin.description);
  195.       if (match && match.length > 0) {
  196.         isValidPlugin = (MIN_FLASH_VERSION <= parseInt(match[1]));
  197.       }
  198.     }
  199.  
  200.     return isValidPlugin;
  201.   },
  202.  
  203.   /**
  204.    * Obtains the URL of the flash player, located in the extension's default
  205.    * folder.
  206.    * @return The URL of the flash player.
  207.    */
  208.   _getFlashURL : function() {
  209.     this._logger.trace("_getFlashURL");
  210.  
  211.     // Flash file name
  212.     const FLASH_FILE_NAME = "firefm.swf";
  213.     let flashFile;
  214.     let flashURL;
  215.  
  216.     try {
  217.       let extensionManager =
  218.         Cc["@mozilla.org/extensions/manager;1"].
  219.           getService(Ci.nsIExtensionManager);
  220.  
  221.       flashFile =
  222.         extensionManager.
  223.           getInstallLocation(FireFM.EXTENSION_UUID).
  224.             getItemLocation(FireFM.EXTENSION_UUID);
  225.       flashFile.append("defaults");
  226.       flashFile.append(FLASH_FILE_NAME);
  227.  
  228.     } catch (e) {
  229.       let directoryService =
  230.         Cc["@mozilla.org/file/directory_service;1"].
  231.           getService(Ci.nsIProperties);
  232.  
  233.       flashFile = directoryService.get("ProfD", Ci.nsIFile);
  234.       flashFile.append("extensions");
  235.       flashFile.append(FireFM.EXTENSION_UUID);
  236.       flashFile.append("defaults");
  237.       flashFile.append(FLASH_FILE_NAME);
  238.     }
  239.  
  240.     flashURL =
  241.       Cc["@mozilla.org/network/protocol;1?name=file"].
  242.         getService(Ci.nsIFileProtocolHandler).getURLSpecFromFile(flashFile);
  243.  
  244.     return flashURL;
  245.   },
  246.  
  247.   /**
  248.    * Installs the permission file required for the embedded flash object to
  249.    * connect to the Internet. If the permission file and entry already exist
  250.    * then the file is not altered.
  251.    * @param aFlashURL The URL of the flash player, used in the permission file.
  252.    */
  253.   _installPermissionFile : function(aFlashURL) {
  254.     this._logger.trace("_installPermissionFile");
  255.  
  256.     let permissionFile = this._getPermissionFile();
  257.     let data =
  258.       "resource://gre/res/hiddenWindow.html\n" +
  259.       "chrome://browser/content/hiddenWindow.xul\n" +
  260.       "chrome://firefm/content/fmVideoDialog.xul\n" +
  261.       decodeURIComponent(aFlashURL);
  262.  
  263.     let foStream =
  264.       Cc["@mozilla.org/network/file-output-stream;1"].
  265.         createInstance(Ci.nsIFileOutputStream);
  266.     let coStream =
  267.       Cc["@mozilla.org/intl/converter-output-stream;1"].
  268.         createInstance(Ci.nsIConverterOutputStream);
  269.  
  270.     // write, create, truncate
  271.     foStream.init(permissionFile, 0x02 | 0x08 | 0x20, 0666, 0);
  272.     coStream.init(foStream, "UTF-8", 0, 0);
  273.     coStream.writeString(data);
  274.     coStream.close();
  275.     foStream.close();
  276.  
  277.     this._logger.debug("Flash permission file written");
  278.   },
  279.  
  280.   /**
  281.    * Obtains a reference to the flash permission file.
  282.    * @return The file permission file reference.
  283.    */
  284.   _getPermissionFile : function() {
  285.     this._logger.trace("_getPermissionFile");
  286.  
  287.     let osIndex = 2;
  288.  
  289.     switch (FireFM.getOperatingSystem()) {
  290.       case FireFM.OS_WINDOWS:
  291.       case FireFM.OS_WINDOWS_VISTA:
  292.         osIndex = 0;
  293.         break;
  294.       case FireFM.OS_MAC:
  295.         osIndex = 1;
  296.         break;
  297.     }
  298.  
  299.     let file =
  300.       Cc["@mozilla.org/file/directory_service;1"].
  301.         getService(Ci.nsIProperties).
  302.           get(LOCATIONS[osIndex], Ci.nsIFile);
  303.  
  304.     // Move towards target path
  305.     for (let i = 0; i < DIR_PATH[osIndex].length; i++) {
  306.       file.append(DIR_PATH[osIndex][i]);
  307.  
  308.       if (!file.exists() || !file.isDirectory()) {
  309.         file.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
  310.       }
  311.     }
  312.  
  313.     file.append(PERMISSION_FILE_NAME);
  314.  
  315.     return file;
  316.   },
  317.  
  318.   /**
  319.    * Injects the embedded flash player object needed to play mp3 files in the
  320.    * hidden window.
  321.    * @param aFlashURL The URL from where to load the flash player.
  322.    */
  323.   _injectFlash : function(aFlashURL) {
  324.     this._logger.trace("_injectFlash");
  325.  
  326.     let win =
  327.       Cc["@mozilla.org/appshell/appShellService;1"].
  328.         getService(Ci.nsIAppShellService).hiddenDOMWindow;
  329.     let doc = win.document;
  330.  
  331.     let playerObj =
  332.       doc.createElementNS("http://www.w3.org/1999/xhtml", "embed");
  333.  
  334.     playerObj.setAttribute("src", aFlashURL);
  335.     playerObj.setAttribute("type", "application/x-shockwave-flash");
  336.     playerObj.setAttribute("id", "firefm-player");
  337.     playerObj.setAttribute("name", "firefm-player");
  338.     playerObj.setAttribute("FlashVars", "id='firefm-player'");
  339.     playerObj.setAttribute("allowScriptAccess", "always");
  340.     playerObj.setAttribute("quality", "high");
  341.  
  342.     doc.documentElement.appendChild(playerObj);
  343.  
  344.     win.onFireFMSoundLoad = function(aId, aSuccess) {
  345.       FireFM.Player.onTrackLoaded(aSuccess);
  346.     };
  347.  
  348.     win.onFireFMSoundComplete = function(aId) {
  349.       FireFM.Player.onTrackFinished();
  350.     };
  351.  
  352.     win.addEventListener(
  353.       "unload",
  354.       function() {
  355.         win.onFireFMSoundLoad = null;
  356.         win.onFireFMSoundComplete = null;
  357.         FireFM.Player.uninitializePlayer();
  358.       },
  359.       false);
  360.  
  361.     return playerObj;
  362.   },
  363.  
  364.   /**
  365.    * Determines whether the extension identified by aExtensionId is intalled.
  366.    * @return True if installed, false otherwise.
  367.    */
  368.   _isExtensionInstalled : function(aExtensionId) {
  369.     this._logger.trace("_isExtensionInstalled");
  370.     return (null != FireFM.Application.extensions.get(aExtensionId));
  371.   },
  372.  
  373.   /**
  374.    * Unblocks the Fire.fm player when it is blocked by certain extensions. A
  375.    * style sheet that removes a special -moz-binding rule for flash embeds is
  376.    * registered. This task has to be performed after every browser window loads.
  377.    */
  378.   _overrideFlashCSS : function() {
  379.     this._logger.trace("_overrideFlashCSS");
  380.  
  381.     let sss =
  382.       Cc["@mozilla.org/content/style-sheet-service;1"].
  383.         getService(Ci.nsIStyleSheetService);
  384.     let overrideSheetURL =
  385.       FireFM.createURI("chrome://firefm/content/overrideFlashblock.css");
  386.  
  387.     sss.loadAndRegisterSheet(overrideSheetURL, sss.USER_SHEET);
  388.     this._logger.info("CSS Flash blocking overridden");
  389.   },
  390.  
  391.   /**
  392.    * Sets the Fire.fm flash player as an allowed object using the NoScript
  393.    * service.
  394.    * @param aFlashURL The URL of the flash player.
  395.    */
  396.   _overrideNoscript : function(aFlashURL) {
  397.     this._logger.trace("overrideNoscript");
  398.  
  399.     try {
  400.       // the extension could be disabled.
  401.       if ("@maone.net/noscript-service;1" in Cc) {
  402.         let noscriptService =
  403.           Cc["@maone.net/noscript-service;1"].getService().wrappedJSObject;
  404.         noscriptService.setAllowedObject(
  405.           aFlashURL, "application/x-shockwave-flash");
  406.       }
  407.     } catch (e) {
  408.       this._logger.warn("Error overriding Noscript: " + e);
  409.     }
  410.   }
  411. };
  412.